package com.ck.common.utils.date;

import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;


/**
 * 日期工具类
 * @author ck
 */
@Slf4j
public class DateTool {

    public static final String YMDHMS = "yyyy-MM-dd HH:mm:ss";
    public static final String YMD = "yyyy-MM-dd";
    public static final String YMDHMS2 = "yyyyMMddHHmmss";
    public static final String HMS = "HH:mm:ss";
    public static final String MD = "MMdd";

    public static Date getDate(int year, int month, int day) {
        Calendar cal = Calendar.getInstance();
        cal.set(year, month - 1, day, 0, 0, 0);
        return cal.getTime();
    }

    /**
     * Get a new date time from a existed date and time
     *
     * @param date
     * @param time
     * @return
     */
    public static Date getDateTime(Date date, Date time) {
        if (null == date && null == time) {
            return null;
        }
        if (null == date) {
            date = DateTool.getSystemDate();
        }
        if (null != date && null == time) {
            time = DateTool.getSystemTimestamp();
        }
        Calendar cal = Calendar.getInstance();
        int year = Integer.parseInt(DateTool.parseDate(date, "yyyy"));
        int month = Integer.parseInt(DateTool.parseDate(date, "M"));
        int day = Integer.parseInt(DateTool.parseDate(date, "dd"));
        int hour = Integer.parseInt(DateTool.parseDate(time, "h"));
        int minute = Integer.parseInt(DateTool.parseDate(time, "m"));
        cal.set(year, month, day, hour, minute);
        return cal.getTime();
    }


    public static boolean isEndOfTheMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        return cal.get(Calendar.DATE) == maxDay;
    }

    public static boolean isEndOfTheYear(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return (cal.get(Calendar.MONTH) == 11) && (cal.get(Calendar.DATE) == 31);
    }

    public static int getLastDayOfTheMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    public static Date getNextWorkingDay() {
        Date nextWorkingDay = DateTool.addDaysToDate(DateTool.getSystemDate(), 1);
        Calendar c = Calendar.getInstance();
        c.setTime(nextWorkingDay);
        int day = c.get(Calendar.DAY_OF_WEEK);
        if (day == Calendar.SUNDAY) {
            nextWorkingDay = DateTool.addDaysToDate(nextWorkingDay, 1);
        }
        return nextWorkingDay;
    }

    public static boolean isStartBeforeEndTime(Date startTime, Date endTime) {
        if (startTime == null || endTime == null) {
            return true;
        }
        return startTime.getTime() <= endTime.getTime();
    }

    public static boolean isStartOfTheMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DATE) == 1;
    }

    public static int getMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.MONTH);
    }

    public static int getYear(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.YEAR);
    }


    public static boolean isStartOfTheYear(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return (cal.get(Calendar.MONTH) == 1) && (cal.get(Calendar.DATE) == 1);
    }

    public static java.sql.Date getSystemDate() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return new java.sql.Date(cal.getTime().getTime());
    }

    public static Timestamp getSystemTimestamp() {
        return new Timestamp(System.currentTimeMillis());
    }

    public static String getDate(Date date, String strFormat) {
        return DateTool.parseDate(date, strFormat);
    }

    public static Date addDate(int type, Date date, int num) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(type, num);
        return new Date(cal.getTime().getTime());
    }

    public static Date addDaysToDate(Date date, int numDays) {
        if (date == null) {
            return null;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DATE, numDays);
        return c.getTime();
    }

    public static Date addHoursToDate(Date date, int numHours) {
        if (date == null) {
            return null;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.HOUR_OF_DAY, numHours);
        return c.getTime();
    }

    public static Date addMinutesToDate(Date date, int numMins) {
        if (date == null) {
            return null;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.MINUTE, numMins);
        return c.getTime();
    }

    public static Date addMonthsToDate(Date date, int numMonths) {
        if (date == null) {
            return null;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.MONTH, numMonths);
        return c.getTime();
    }

    public static Date addYearsToDate(Date date, int numYears) {
        if (date == null) {
            return null;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.YEAR, numYears);
        return c.getTime();
    }

    public static String parseDate(Date date, String formatStr) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(formatStr);
        if (date == null) {
            return null;
        } else {
            return dateFormat.format(date);
        }
    }

    public static Date resetTime(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    public static Date toDate(String strDateTime, String dateTimeFormat) {
        if ((strDateTime == null) || (strDateTime.length() == 0)
                || (dateTimeFormat == null) || (dateTimeFormat.length() == 0)) {
            return null;
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat(dateTimeFormat);
        Date date = dateFormat.parse(strDateTime, new ParsePosition(0));
        if (date == null) {
            return null;
        }
        String dateStr = parseDate(date, dateTimeFormat);
        if (!strDateTime.equals(dateStr)) {
            return null;
        }
        return date;
    }

    public static Timestamp toTimestamp(String dateTimeStr, String dateTimeFormat) {
        return toTimestamp(toDate(dateTimeStr, dateTimeFormat));
    }

    public static Timestamp toTimestamp(Date date) {
        if (date == null) {
            return null;
        }
        return new Timestamp(date.getTime());
    }

    public static Date toDate(Timestamp timeStamp) {
        if (timeStamp == null) {
            return null;
        }

        return new Date(timeStamp.getTime());
    }

    public static String toTwoDigits(String number) {
        return StringUtils.leftPad(number, 2, "0");
    }

    public static Date firstDayOfWeek(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.setFirstDayOfWeek(0);
        int year = DateTool.getYear(date);
        int month = DateTool.getMonth(date) + 1;
        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) - 2;
        int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
        if (dayOfWeek < 0) {
            dayOfWeek += 7;
        }
        return DateTool.getDate(year, month, dayOfMonth - dayOfWeek);
    }

    public static Date lastDayOfWeek(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.setFirstDayOfWeek(0);
        int year = DateTool.getYear(date);
        int month = DateTool.getMonth(date) + 1;
        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) - 2;
        int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
        return DateTool.getDate(year, month, dayOfMonth - dayOfWeek + 6);
    }

    public static int getFirstDayOfWeekInMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) - 2;
        int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
        return dayOfMonth - dayOfWeek;
    }

    /**
     * 根据增减天数获取新日期
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return str 返回之间的"日 小时 分钟"
     */
    public static String getDateDiff(Date startDate, Date endDate) {
        String str = "";
        Calendar ca1 = Calendar.getInstance();
        Calendar ca2 = Calendar.getInstance();
        ca1.setTime(startDate);
        ca2.setTime(endDate);
        int distanceDay = ca2.get(Calendar.DAY_OF_MONTH) - ca1.get(Calendar.DAY_OF_MONTH);
        int distanceHour = ca2.get(Calendar.HOUR_OF_DAY) - ca1.get(Calendar.HOUR_OF_DAY);
        int distanceMin = ca2.get(Calendar.MINUTE) - ca1.get(Calendar.MINUTE);
        if (distanceDay != 0) {
            str = str + distanceDay + "天";
        }
        str = str + distanceHour + "小时" + distanceMin + "分钟";
        return str;

    }

    /**
     * 计算时间差
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return str 返回之间的秒"
     */
    public static int getDateDiffSec(Date startDate, Date endDate) {
        int sec = 0;
        Calendar ca1 = Calendar.getInstance();
        Calendar ca2 = Calendar.getInstance();
        ca1.setTime(endDate);
        ca2.setTime(startDate);
        double timeLong = ca1.getTimeInMillis() - ca2.getTimeInMillis();
        sec = (int) (timeLong / 1000);
        return sec;
    }

    /**
     * 计算时间差
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static double getDateDiffSecFloat(Date startDate, Date endDate) {
        int sec = 0;
        Calendar ca1 = Calendar.getInstance();
        Calendar ca2 = Calendar.getInstance();
        ca1.setTime(endDate);
        ca2.setTime(startDate);
        double timeLong = ca1.getTimeInMillis() - ca2.getTimeInMillis();
//        sec = (int) (timeLong / 1000);
        return timeLong / 1000.0;
    }

    /**
     * 根据增减天数获取新日期
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return str 返回之间的天数"
     */
    public static int getDateDiffDay(Date startDate, Date endDate) {
        int day = 0;
        Calendar ca1 = Calendar.getInstance();
        Calendar ca2 = Calendar.getInstance();
        ca1.setTime(endDate);
        ca2.setTime(startDate);
        double timeLong = ca1.getTimeInMillis() - ca2.getTimeInMillis();
        day = (int) (timeLong / (1000 * 60 * 60 * 24));
        return day;

    }

    /**
     * 根据增减天数获取新日期
     *
     * @param inDate     传入的日期
     * @param AddDateInt 要增减的天数
     * @return Date 返回日期
     */
    public static Date getDateAddInt(Date inDate, int addDateInt) {
        Calendar theCalendar = new GregorianCalendar();
        Date returnDate = new Date();

        if (inDate != null) {
            String dateStr = parseDate(inDate, YMDHMS);
            theCalendar.set(Integer.parseInt(dateStr.substring(0, 4)), Integer
                            .parseInt(dateStr.substring(5, 7)) - 1, Integer
                            .parseInt(dateStr.substring(8, 10))
                            + addDateInt, Integer.parseInt(dateStr.substring(11, 13)),
                    Integer.parseInt(dateStr.substring(14, 16)), Integer
                            .parseInt(dateStr.substring(17, 19)));
            returnDate = new Date();
            returnDate = theCalendar.getTime();
        }

        return returnDate;
    }

    public static Date toTime(String dateStr, String formatStr) {
        Date startTime = null;
        if (dateStr == null && formatStr == null) {
            return null;
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
            startTime = sdf.parse(dateStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return startTime;
    }

    /**
     * 判断是否在一个时间段内
     *
     * @param startTimeStr
     * @param endTimeStr
     * @param timeStr
     * @param formatStr
     * @return
     */
    public static boolean isBetweenTimes(String startTimeStr, String endTimeStr, String timeStr, String formatStr) {
        boolean flag = false;
        Date startTime = null;
        Date endTime = null;
        Date time = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(formatStr);
            startTime = sdf.parse(startTimeStr);
            endTime = sdf.parse(endTimeStr);
            time = sdf.parse(timeStr);
            if (startTime.before(time) && endTime.after(time)) {
                flag = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }


    /**
     * 同当前时间比较时间差
     *
     * @param timestamp
     * @param diffMinute
     * @return
     */
    public static boolean timeDiff(String timestamp, Integer diffMinute) {
        boolean flag = false;
        Date date = DateTool.toDate(timestamp, "yyyyMMddHHmmss");
        if (date != null) {
            Date now = new Date();
            long l = now.getTime() - date.getTime();
            long day = l / (24 * 60 * 60 * 1000);
            long hour = (l / (60 * 60 * 1000) - day * 24);
            long min = ((l / (60 * 1000)) - day * 24 * 60 - hour * 60);
            long s = (l / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
            if (day != 0 || hour != 0 || min < 0 || min > diffMinute) {
                flag = true;
            }
        } else {
            flag = true;
        }
        return flag;
    }

    /**
     * 取当月的最后天日期
     *
     * @param currDate
     * @return
     */
    public static Date getLastDayOfMonth(Date currDate) {
        Calendar cDay1 = Calendar.getInstance();
        cDay1.setTime(currDate);
        int lastDay = cDay1.getActualMaximum(Calendar.DAY_OF_MONTH);
        Date lastDate = cDay1.getTime();
        return lastDate;
    }

    public static int obtainPartition(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);

        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DATE);
        return month * 100 + day;
    }

    /**
     * 获取时段分区
     *
     * @param date
     * @return
     */
    public static int hourPart(Date date) {
        if (date == null) {
            date = new Date();
        }

        Calendar ca = Calendar.getInstance();
        ca.setTime(date);

        return ca.get(Calendar.HOUR_OF_DAY);
    }


    /**
     * 获取当前时间
     *
     * @return
     */
    public static String getNowDate() {
        return getNowDate(YMDHMS);
    }

    /**
     * 获取当前时间
     *
     * @param strFormat
     * @return
     */
    public static String getNowDate(String strFormat) {
        return DateTool.parseDate(new Date(), strFormat);
    }

    public static boolean isValidDate(String str, String formatStr) {
        boolean convertSuccess = true;
        // 指定日期格式为四位年/两位月份/两位日期，注意yyyy/MM/dd区分大小写；
        SimpleDateFormat format = new SimpleDateFormat(formatStr);
        try {
            // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
            format.setLenient(false);
            format.parse(str);
        } catch (ParseException e) {
            convertSuccess = false;
        }
        return convertSuccess;
    }


    /**
     * 入参：开始时间，结束时间，精确等级
     *
     * @param startDate
     * @param endDate
     * @param level
     * @return
     */
    public static String getDateBetween(Date startDate, Date endDate, BetweenFormatter.Level level) {
        if (startDate != null && endDate != null) {
            return DateUtil.formatBetween(startDate, endDate, level);
        }
        return "";
    }

    public static int getMinuteDiff(Date startDate, Date endDate) {
        System.out.println("开始时间：" + DateUtil.format(startDate, YMDHMS));
        System.out.println("当前时间:" + DateUtil.format(endDate, YMDHMS));
        long startTime = startDate.getTime();
        long endTime = endDate.getTime();
        int minutes = (int) ((endTime - startTime) / (1000 * 60));
        if (minutes != 0) {
            return minutes;
        }
        return 0;
    }


}
